home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software written by Ken Arnold and
- * published in UNIX Review, Vol. 6, No. 8.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement: ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)popen.c 5.14 (Berkeley) 6/1/90";
- #endif /* LIBC_SCCS and not lint */
-
- #include <sys/param.h>
- #define _BSD_SIGNALS /* for IRIX, to use BSD signals */
- #include <sys/signal.h>
- #include <sys/wait.h>
- #include <errno.h>
- #include <stdio.h>
- #include <unistd.h>
- int bzero(void *, int); /* this isn't in a header file !? */
- #include <paths.h>
- #include <string.h>
- #include <stdlib.h>
-
- static pid_t *pids;
-
- /*
- * Original popen() code extended to open multiple pipes to a process
- *
- * By Kevin Russo
- * SFA, Inc/US Naval Research Lab, Code 5133
- * March 14, 1991
- *
- * Calling sequence:
- * FILE (*popen_ioe(const char *command, const char *type))[3];
- * FILE ** popen_ioe(const char *command, const char *type);
- *
- * Arguments:
- * type - a string containing any of the letters "rwe"
- * command - a shell command
- *
- * Returns:
- * FILE **ptr;
- *
- * ptr[0] is a FILE pointer to the command's stdin
- * ptr[1] is a FILE pointer to the command's stdout
- * ptr[2] is a FILE pointer to the command's stderr
- *
- * If a connection was not requested, that ptr is NULL.
- * type may contain r and/or w and/or e, but must contain one of them.
- */
-
- FILE **
- popen_ioe(const char *program, const char *type)
- {
- FILE **iop;
- int pdes[2], fds, pid;
- int pdes2[2], pdes3[2];
- int in, out, err;
-
- if (pids == NULL) {
- if ((fds = getdtablesize()) <= 0)
- return (NULL);
- if((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
- return (NULL);
- bzero((void *)pids, fds * sizeof(pid_t));
- }
- if ((iop = (FILE **) malloc(3 * sizeof(FILE **))) == NULL)
- return (NULL);
- bzero((void *)iop, 3 * sizeof(FILE **));
-
- in = (int) strchr(type, 'r');
- out = (int) strchr(type, 'w');
- err = (int) strchr(type, 'e');
- if(!in && !out && !err) /* have to set one of them */
- return (NULL);
-
- if(in && pipe(pdes) < 0)
- return (NULL);
- if(out && pipe(pdes2) < 0)
- return (NULL);
- if(err && pipe(pdes3) < 0)
- return (NULL);
- /*
- if (pipe(pdes) < 0 || pipe(pdes2) < 0 || pipe(pdes3) < 0)
- return (NULL);
- */
- switch (pid = fork()) {
- case -1: /* error */
- if (in) { (void) close(pdes[0]); (void) close(pdes[1]); }
- if (out) { (void) close(pdes2[0]); (void) close(pdes2[1]); }
- if (err) { (void) close(pdes3[0]); (void) close(pdes3[1]); }
- return (NULL);
- /* NOTREACHED */
- case 0: /* child */
- if (in) {
- if (pdes[1] != STDOUT_FILENO) {
- (void) dup2(pdes[1], STDOUT_FILENO);
- (void) close(pdes[1]);
- }
- (void) close(pdes[0]);
- }
- if (out) {
- if (pdes2[0] != STDIN_FILENO) {
- (void) dup2(pdes2[0], STDIN_FILENO);
- (void) close(pdes2[0]);
- }
- (void) close(pdes2[1]);
- }
- if (err) {
- if (pdes3[1] != STDERR_FILENO) {
- (void) dup2(pdes3[1], STDERR_FILENO);
- (void) close(pdes3[1]);
- }
- (void) close(pdes3[0]);
- }
- execl(_PATH_BSHELL, "sh", "-c", program, NULL);
- _exit(127);
- /* NOTREACHED */
- }
- /* parent; assume fdopen can't fail... */
- if (in) {
- iop[0] = fdopen(pdes[0], "r");
- (void) close(pdes[1]);
- pids[fileno(iop[0])] = pid;
- }
- if(out) {
- iop[1] = fdopen(pdes2[1], "w");
- (void) close(pdes2[0]);
- pids[fileno(iop[1])] = pid;
- }
- if(err) {
- iop[2] = fdopen(pdes3[0], "r");
- (void) close(pdes3[1]);
- pids[fileno(iop[2])] = pid;
- }
- return (iop);
- }
-
- int
- pclose_ioe(FILE *iop[3])
- {
- register int fdes, fdes1, fdes2, fdes3;
- int omask;
- /* union wait pstat;*/
- int pstat;
- pid_t pid;
-
- /*
- * pclose returns -1 if stream is not associated with a
- * `popened' command, if already `pclosed', or waitpid
- * returns an error.
- */
- if (pids == NULL)
- return (-1);
- if (iop[0] != 0 && pids[fdes1 = fileno(iop[0])] == 0 ||
- iop[1] != 0 && pids[fdes2 = fileno(iop[1])] == 0 ||
- iop[2] != 0 && pids[fdes3 = fileno(iop[2])] == 0)
- return (-1);
- /* any fdes will do since all the pids are the same */
- if(! iop[0]) { (void) fclose(iop[0]); fdes = fdes1; }
- if(! iop[1]) { (void) fclose(iop[1]); fdes = fdes2; }
- if(! iop[2]) { (void) fclose(iop[2]); fdes = fdes3; }
- omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
- do {
- pid = waitpid(pids[fdes], &pstat, 0);
- } while (pid == -1 && errno == EINTR);
- (void) sigsetmask(omask);
- pids[fdes1] = 0;
- pids[fdes2] = 0;
- pids[fdes3] = 0;
- /*return (pid == -1 ? -1 : pstat.w_status);*/
- return (pid == -1 ? -1 : pstat);
- }
-